package com.xposed.openfire.smack.xmpp;

import android.text.TextUtils;
import android.util.Log;

import com.xposed.openfire.smack.APPOpenfireSmack;
import com.xposed.openfire.smack.entity.ChatMessage;
import com.xposed.openfire.smack.entity.ChatRecord;
import com.xposed.openfire.smack.entity.SessionMessage;
import com.xposed.openfire.smack.utils.JsonUtils;
import com.xposed.openfire.smack.utils.LogUtils;

import org.greenrobot.eventbus.EventBus;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.chat.ChatManagerListener;
import org.jivesoftware.smack.chat2.Chat;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.chat2.IncomingChatMessageListener;
import org.jivesoftware.smack.chat2.OutgoingChatMessageListener;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.StanzaTypeFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.roster.RosterEntry;
import org.jivesoftware.smack.roster.RosterListener;
import org.jivesoftware.smack.roster.RosterLoadedListener;
import org.jivesoftware.smack.roster.packet.RosterPacket;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.address.packet.MultipleAddresses;
import org.jivesoftware.smackx.iqregister.AccountManager;
import org.jivesoftware.smackx.muc.HostedRoom;
import org.jivesoftware.smackx.muc.MultiUserChatManager;
import org.jivesoftware.smackx.ping.PingFailedListener;
import org.jivesoftware.smackx.ping.PingManager;
import org.jivesoftware.smackx.pubsub.PubSubManager;
import org.jivesoftware.smackx.pubsub.Subscription;
import org.jivesoftware.smackx.search.ReportedData;
import org.jivesoftware.smackx.search.UserSearch;
import org.jivesoftware.smackx.search.UserSearchManager;
import org.jivesoftware.smackx.xdata.Form;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.DomainBareJid;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Localpart;
import org.jxmpp.stringprep.XmppStringprepException;

import java.io.IOException;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public class XmppConnection implements ConnectionListener, StanzaListener, IncomingChatMessageListener, OutgoingChatMessageListener, PingFailedListener {

    private final static String XMPP_DOMAIN = "192.168.1.113";
    private final static int XMPP_PORT = 5222;

    private static volatile XmppConnection mXmppConnection = null;
    private AbstractXMPPConnection connection = null;

    public static XmppConnection getInstance() {
        if (mXmppConnection == null) synchronized (XmppConnection.class) {
            if (mXmppConnection == null)
                mXmppConnection = new XmppConnection();
        }
        return mXmppConnection;
    }

    public void openConnection() {
        if (connection != null) {
            return;
        }
        try {
            XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
                    //设置openfire服务器名称
                    .setXmppDomain(XMPP_DOMAIN)
                    //设置openfire主机IP
                    .setHostAddress(InetAddress.getByName(XMPP_DOMAIN))
                    //设置端口号：默认5222
                    .setPort(XMPP_PORT)
                    //设置离线状态
                    .setSendPresence(false)
                    //设置开启压缩，可以节省流量
                    .setCompressionEnabled(true)
                    //禁用SSL连接
                    .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
                    .build();
            //需要经过同意才可以添加好友
            Roster.setDefaultSubscriptionMode(Roster.SubscriptionMode.manual);
            //初始化连接
            connection = new XMPPTCPConnection(config);
            //连接监听
            connection.addConnectionListener(this);
            //用户状态监听
            connection.addSyncStanzaListener((this), new AndFilter(new StanzaTypeFilter(Presence.class)));
            //连接
            connection.connect();
        } catch (XMPPException | SmackException | IOException | InterruptedException e) {
            LogUtils.e("异常报告：" + e.getMessage());
        }
    }

    /**
     * 关闭连接
     */
    public void closeConnection() {
        if (connection == null) {
            return;
        }
        if (connection.isConnected()) {
            connection.disconnect();
        }
    }

    /**
     * 判断连接是否通过了身份验证
     * 即是否已登录
     *
     * @return true/false
     */
    public boolean isAuthenticated() {
        return connection != null && connection.isConnected() && connection.isAuthenticated();
    }

    /**
     * 用户登录
     *
     * @param userName 用户名
     * @param password 用户密码
     */
    public boolean userLogin(String userName, String password) {
        if (connection == null) {
            return false;
        }
        try {
            if (!connection.isConnected()) {
                connection.connect();
            }
            connection.login(userName, password);
            if (connection.isAuthenticated()) {
                setPresence(1);
                //注册服务器ping
                PingManager pingManager = PingManager.getInstanceFor(connection);
                pingManager.setPingInterval(10);
                pingManager.registerPingFailedListener(this);
                //创建消息监听
                ChatManager chatManager = ChatManager.getInstanceFor(connection);
                chatManager.addOutgoingListener(this);
                chatManager.addIncomingListener(this);
                //接收离线消息监听

                //好友请求验证监听
                Roster.setDefaultSubscriptionMode(Roster.SubscriptionMode.manual);
//                Roster.getInstanceFor(connection).addRosterListener(new RosterListener() {
//                    @Override
//                    public void entriesAdded(Collection<Jid> addresses) {
//                        LogUtils.e("entriesAdded");
//                    }
//
//                    @Override
//                    public void entriesUpdated(Collection<Jid> addresses) {
//                        LogUtils.e("entriesUpdated");
//                    }
//
//                    @Override
//                    public void entriesDeleted(Collection<Jid> addresses) {
//                        LogUtils.e("entriesDeleted");
//                    }
//
//                    @Override
//                    public void presenceChanged(Presence presence) {
//                        LogUtils.e("presenceChanged");
//                    }
//                });
                //
                APPOpenfireSmack.setEntityFullJid(connection.getUser());
                return true;
            }
        } catch (SmackException | IOException | XMPPException | InterruptedException e) {
            LogUtils.e("异常报告：" + e.getMessage());
        }
        return false;
    }

    /**
     * 用户注册
     *
     * @param userName 用户名
     * @param password 用户密码
     * @param map      用户属性
     */
    public boolean userLogon(String userName, String password, Map<String, String> map) {
        if (connection != null) try {
            AccountManager account = AccountManager.getInstance(connection);
            account.sensitiveOperationOverInsecureConnection((true));
            if (map == null) {
                account.createAccount(Localpart.from(userName), password);
            } else {
                account.createAccount(Localpart.from(userName), password, map);
            }
            return true;
        } catch (XmppStringprepException | InterruptedException | XMPPException | SmackException e) {
            LogUtils.e("异常报告：" + e.getMessage());
        }
        return false;
    }

    /**
     * 用户注册
     *
     * @param userName 用户名
     * @param password 用户密码
     */
    public boolean userLogon(String userName, String password) {
        return userLogon(userName, password, null);
    }

    /**
     * 获取所有好友信息
     *
     * @return List<RosterEntry>
     */
    public List<RosterEntry> getAllEntries() {
        if (connection == null)
            return null;
        return new ArrayList<>(Roster.getInstanceFor(connection).getEntries());
    }


    public RosterEntry getEntries(String jid) {
        if (connection == null)
            return null;

        try {
            return Roster.getInstanceFor(connection).getEntry(JidCreate.from(jid).asBareJid());
        } catch (XmppStringprepException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 设置用户状态
     *
     * @param status 状态
     */
    public void setPresence(int status) {
        if (connection == null) {
            return;
        }
        Presence stanza = null;
        switch (status) {
            case 0://在线
                stanza = new Presence(Presence.Type.available);
                break;
            case 1://空闲
                stanza = new Presence(Presence.Type.available);
                stanza.setMode(Presence.Mode.chat);
                break;
            case 2://忙碌
                stanza = new Presence(Presence.Type.available);
                stanza.setMode(Presence.Mode.dnd);
                break;
            case 3://离开
                stanza = new Presence(Presence.Type.available);
                stanza.setMode(Presence.Mode.away);
                break;
            case 4://离线
                stanza = new Presence(Presence.Type.unavailable);
                break;
            default:
                break;
        }
        if (stanza != null) try {
            connection.sendStanza(stanza);
        } catch (SmackException.NotConnectedException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建聊天窗口
     *
     * @param toUserName 接收者用户名
     */
    public Chat createChatWindow(String toUserName) {
        if (TextUtils.isEmpty(toUserName))
            return null;
        toUserName = toUserName + "@" + connection.getXMPPServiceDomain().toString();
        try {
            return ChatManager.getInstanceFor(connection)
                    .chatWith(JidCreate.entityBareFrom(toUserName));
        } catch (XmppStringprepException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 发送消息
     *
     * @param chat 聊天窗口
     * @param msg  发送数据
     */
    public void sendChatMessage(Chat chat, String msg) {
        if (chat == null) {
            return;
        }
        try {
            Message message = new Message();
            message.setBody(msg);
            message.setType(Message.Type.chat);
            chat.send(message);
        } catch (SmackException.NotConnectedException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送消息
     *
     * @param toUserName 接收者用户名
     * @param msg        发送数据
     */
    public void sendChatMessage(String toUserName, String msg) {
        try {
            Chat chat = createChatWindow(toUserName);
            Message message = new Message();
            message.setBody(msg);
            message.setType(Message.Type.chat);
            chat.send(message);
        } catch (SmackException.NotConnectedException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加好友
     *
     * @param jidString 用户jid
     * @param again     命名
     */
    public void addCreateFriend(String jidString, String again, String[] groups) {
        try {
            BareJid bareJid = JidCreate.from(jidString).asBareJid();
            if (TextUtils.isEmpty(again)) {
                again = jidString.substring(0, jidString.indexOf("@"));
            }
            Roster.getInstanceFor(connection).createEntry(bareJid, again, groups);
        } catch (XmppStringprepException | InterruptedException | SmackException.NotLoggedInException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
            e.printStackTrace();
            LogUtils.e("异常报告：" + e.getMessage());
        }
    }

    /**
     * 订阅
     *
     * @param jidString 用户jid
     * @param type      订阅类型
     */
    public void subscribed(String jidString, Presence.Type type) {
        if (connection != null) try {
            Presence presence = new Presence(type);
            presence.setTo(JidCreate.from(jidString));
            connection.sendStanza(presence);
        } catch (XmppStringprepException | SmackException.NotConnectedException | InterruptedException e) {
            e.printStackTrace();
        }
    }


    public Map<EntityBareJid, HostedRoom> getHostedRoom() {

        MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
        try {
            //serviceNames->conference.106.14.20.176
            List<DomainBareJid> serviceNames = manager.getMucServiceDomains();
            for (int i = 0; i < serviceNames.size(); i++) {
                LogUtils.e(serviceNames.size() + "," + manager.getRoomsHostedBy(serviceNames.get(i)));
                return manager.getRoomsHostedBy(serviceNames.get(i));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

//    public void userSearch() {
//        UserSearchManager searchManager = new UserSearchManager(connection);
//        try {
//            DomainBareJid searchService = connection.getXMPPServiceDomain();
//            Form form = searchManager.getSearchForm(searchService);
//            Form form1 = form.createAnswerForm();
//            form.setAnswer("name", "lemlin");
//            ReportedData data = searchManager.getSearchResults(form1, searchService);
//            LogUtils.e("------" + JsonUtils.objectToString(data));
//        } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | InterruptedException e) {
//            e.printStackTrace();
//            LogUtils.e("异常报告：" + e.getMessage());
//        }
//    }

    /*------------------------------------连接监听----------------------------------------------*/

    /**
     * 连接成功
     */
    @Override
    public void connected(XMPPConnection connection) {
        LogUtils.e("连接成功");
    }

    /**
     * 认证成功
     */
    @Override
    public void authenticated(XMPPConnection connection, boolean resumed) {
        LogUtils.e("认证成功");
    }

    /**
     * 关闭连接
     */
    @Override
    public void connectionClosed() {
        LogUtils.e("关闭连接");
    }

    /**
     * 连接异常
     */
    @Override
    public void connectionClosedOnError(Exception e) {
        LogUtils.e("连接异常：" + e.getMessage());
    }

    /*------------------------------------用户状态监听----------------------------------------------*/

    @Override
    public void processStanza(Stanza packet) {
        if (packet instanceof Presence) {
            EventBus.getDefault().post(packet);
        }
    }


    /*------------------------------------消息发送接收监听----------------------------------------------*/

    /**
     * 消息发送监听
     */
    @Override
    public void newOutgoingMessage(EntityBareJid to, Message message, Chat chat) {
        LogUtils.e("发送消息：" + JsonUtils.objectToString(message));
        ChatMessage msg = new ChatMessage();
        msg.setName(to.asBareJid().getLocalpartOrNull().intern());
        msg.setFrom(connection.getUser().asBareJid().getLocalpartOrNull().intern());
        msg.setTo(message.getTo().asBareJid().getLocalpartOrNull().intern());
        msg.setMsg(message.getBody());
        SimpleDateFormat sdf = new SimpleDateFormat(("yyyy年MM月dd日 HH:mm:ss"), Locale.CHINA);
        msg.setTime(sdf.format(new Date(System.currentTimeMillis())));
        msg.setMsgType("TEXT");
        EventBus.getDefault().post(msg);
    }

    /**
     * 消息接收监听
     */
    @Override
    public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
        LogUtils.e("接收消息：" + JsonUtils.objectToString(message));
        ChatMessage msg = new ChatMessage();
        msg.setName(from.asBareJid().getLocalpartOrNull().intern());
        msg.setFrom(message.getFrom().asBareJid().getLocalpartOrNull().intern());
        msg.setTo(message.getTo().asBareJid().getLocalpartOrNull().intern());
        msg.setMsg(message.getBody());
        SimpleDateFormat sdf = new SimpleDateFormat(("yyyy年MM月dd日 HH:mm:ss"), Locale.CHINA);
        msg.setTime(sdf.format(new Date(System.currentTimeMillis())));
        msg.setMsgType("TEXT");
        EventBus.getDefault().post(msg);
    }

    /*------------------------------------PING监听----------------------------------------------*/

    /**
     * 服务器ping失败时调用
     */
    @Override
    public void pingFailed() {
        LogUtils.e("服务器ping失败" + connection.isConnected() + "," + connection.isAuthenticated());
    }
}
